/*
Copyright 2008  Four Roads LLC conact@4-roads.com

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either 
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with this library.  If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections;
using CommunityServer.Components;
using CA = ComponentArt.Web.UI;

namespace FourRoads.Links.Controls
{
	/// <summary>
	/// Summary description for BasePermissionsGridControl.
	/// </summary>
	public abstract class BasePermissionsGridControl : BaseGridControl
	{
		protected Hashtable permissionChanges;

		protected abstract ApplicationType applicationType{get;}
		protected abstract Type PermissionType{get;}

		#region Public Properties

		private int sectionID = -1;
		public int SectionID
		{
			get { return sectionID; }
			set { sectionID = value;}
		}

		#endregion

		public BasePermissionsGridControl()
		{

		}

		override protected void OnInit(EventArgs e)
		{
			this.Load += new System.EventHandler(this.BasePage_Load);
			base.OnInit(e);

			this.Grid.ItemCheckChanged += new CA.Grid.ItemCheckChangedEventHandler(this.Grid_ItemCheckChanged);
		}

		private void BasePage_Load(object sender, EventArgs e)
		{
			if(!Page.IsPostBack && !this.PanelPage.IsCallBack)
			{
				buildGrid();
				Grid.DataBind();
			}
		}

		private Permission GetPermission(string permission)
		{
			switch(permission)
			{
				case "AddLinks":
					return (Permission)ResLinkPermissionEnum.AddLinks;
				case "AddComments":
					return (Permission)ResLinkPermissionEnum.AddComments;
				case "EditLinks":
					return (Permission)ResLinkPermissionEnum.EditLinks;
				case "Moderate":
					return (Permission)ResLinkPermissionEnum.Moderate ;
				case "RemoveLinks":
					return (Permission)ResLinkPermissionEnum.RemoveLinks;
				case "ReportDeadLinks":
					return (Permission)ResLinkPermissionEnum.ReportDeadLinks;
				case "ViewLink":
					return (Permission)ResLinkPermissionEnum.ViewLink;
			}

			return Permission.Undefined;
		}

		protected abstract PermissionBase LoadPermission(int SectionID, Guid roleID);
		protected abstract ArrayList GetSectionPermissions(int SectionID);
		protected abstract PermissionBase NewPermission();

		protected virtual bool IsNew(PermissionBase permission)
		{
			return permission == null || permission.SectionID == -1;
		}

		protected virtual bool CreateFromDefault(PermissionBase permission)
		{
			return permission != null && permission.SectionID == -1;
		}

		protected virtual void UpdatePermissions(Guid roleID, ArrayList roleChanges)
		{
			PermissionBase permission = null;
			bool isNew = false;
			permission = LoadPermission(SectionID, roleID);
			
			if(IsNew(permission))
			{
				PermissionBase originalp = permission;

				isNew = true;
				permission = NewPermission();
				permission.SectionID = SectionID;
				permission.RoleID = roleID;

				//if we are transitioning from a default permission to a seciton permission 
				//copy the existing permissions for this role
				if(CreateFromDefault(originalp))
				{
					permission.AllowMask = originalp.AllowMask;
					permission.DenyMask = originalp.DenyMask;
				}
			}
			permission.ApplicationType = applicationType;
			
			foreach(GridCheckChange e in roleChanges)
			{
				AccessControlEntry access = (e.Checked)? AccessControlEntry.Allow: AccessControlEntry.Deny;
				permission.SetBit(GetPermission(e.Column.DataField.ToString()), access);
			}

			SavePermission(permission, isNew);
		}



		protected void SavePermission(PermissionBase p, bool isNew)
		{
			if(isNew)
			{
				p.SettingsID = CSContext.Current.SettingsID;
				Permissions.AddPermission(p);
			}
			else
			{
				Permissions.UpdatePermission(p) ;
			}
		}


		protected override void buildGrid()
		{
			ArrayList unsortedRoles = GetSectionPermissions(SectionID);
			if(SectionID != -1)
				unsortedRoles.AddRange(GetSectionPermissions(-1));
			
			//The list will have any section specific permissions followed by the default permissions
			//Remove the role default permissions if a section permission is specified
			SortedList roles = new SortedList();

			foreach(PermissionBase p in unsortedRoles)
			{
				if(!roles.ContainsKey(p.Name))
					roles.Add(p.Name, p);
			}

			//The grid will only show checkboxes in edit mode if the data source is a DataTable
			Grid.DataSource = CADataConverter.ToDataTable((IList)roles.Values, PermissionType);

			this.RecordCount = roles.Count;

			ApplyUserSettings();
			
			//Override the default page size because we don't have a pager
			Grid.PageSize = 99999;
			Grid.ShowFooter = false;
			Grid.ShowHeader = false;

		}

		public void Save()
		{
			if(permissionChanges != null)
			{
				foreach(object key in permissionChanges.Keys)
					this.UpdatePermissions((Guid)key, (ArrayList)permissionChanges[key]) ;
			}

			if (SectionID > 0)
			{
				ResLinkSection.ClearSectionCache(SectionID);

				buildGrid();
				Grid.DataBind();
			}
			else
			{
				//Clear the cache of data as the permissions of all sections has changed
				//And then repost to this page
				ResLinkSection.ClearAllSectionCache();
				Response.Redirect(Request.RawUrl);
			}
		}

		public void Grid_ItemCheckChanged(object sender, CA.GridItemCheckChangedEventArgs e)
		{
			//This event is raised on every callback. We only need to handle it on a postback/click
			//This event is raised for each checkmark in the order they were clicked on the screen
			//			if(!this.ForumPage.IsCallBack) 
			//			{
			//				if(permissionChanges == null)
			//					permissionChanges = new ArrayList();
			//
			//				//put the checked vaules into the item
			//				permissionChanges.Add(new GridCheckChange(e.Item , e.Column, e.Checked));
			//			}

			if(!this.PanelPage.IsCallBack) 
			{
				if(permissionChanges == null)
					permissionChanges = new Hashtable();

				Guid role = new Guid(e.Item["RoleIDString"].ToString());
				ArrayList roleChanges;
				if(permissionChanges.ContainsKey(role))
					roleChanges = (ArrayList)permissionChanges[role];
				else
					roleChanges = new ArrayList();


				//put the checked vaules into the item
				roleChanges.Add(new GridCheckChange(e.Item , e.Column, e.Checked));


				if(permissionChanges.ContainsKey(role))
					permissionChanges[role] = roleChanges;
				else
					permissionChanges.Add(role, roleChanges) ;

			}
		}
	}
}
